#include <my_header.h>
// 多人聊天 服务端作为中间转发
// 服务端
/* Usage:  ./4_server_chat*/
// 定义一个结构体，用来描述某一个客户端的链接状态
typedef struct clinet_s
{
    int net_fd; // 服务于客户端的socket对象
    int alive;  // 查看是否不在全连接队列
}client_t;
int main(void){                                  
    // 服务端IP地址和端口
    char *ip = "192.168.229.128";
    char *port = "8080";

    // 定义socket对象
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    ERROR_CHECK(socket_fd, -1, "socket");

    // 超时重连
    int reuse = 1;
    int res_set = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    ERROR_CHECK(res_set, -1, "setsockopt");
    // 构建 struct sockaddr 结构体类型
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(port));
    server_addr.sin_addr.s_addr = inet_addr(ip);

    // 绑定端口和ip地址
    int res_bind = bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    ERROR_CHECK(res_bind, -1, "bind");

    // 监听队列的套接字
    int res_lis  = listen(socket_fd, 10);
    ERROR_CHECK(res_lis, -1, "listen");

    client_t list[100]; // 用于存储连接的数组
    memset(list, 0, sizeof(list));
    int size = 0;   // 记录数组中存储到那个位置

    // 
    fd_set base_set;
    FD_ZERO(&base_set);
    FD_SET(socket_fd, &base_set);

    // 程序一直运行
    while(1)
    {

        fd_set set;
        memcpy(&set, &base_set, sizeof(base_set));
        select(100, &set, NULL, NULL, NULL);

        if(FD_ISSET(socket_fd, &set))
        {
            // 有新的连接，存储，监听
            int net_fd = accept(socket_fd, NULL, NULL);
            // 记录这个链接
            list[size].net_fd = net_fd;
            list[size].alive = 1;
            size++;
            // 放入监听
            FD_SET(net_fd, &base_set);
        }
        // 需呀检测，是不是某个客户端发送信息，导致select就绪
        // 遍历所有连接
        for(int i=0; i<size; i++)
        {
            if(list[1].alive == 1 && FD_ISSET(list[i].net_fd, &set))
            {
                // 这个i位置的客户端发送信息；读取信息转发
                char buf[60] = {0};
                int ret_recv = recv(list[i].net_fd, buf, sizeof(buf), 0);
                if(ret_recv == 0)
                {
                    printf("--连接断开-- \n");
                    // 客户端已断开连接，修改状态，移除监听
                    list[i].alive = 0;
                    FD_CLR(list[i].net_fd, &base_set);
                    close(list[i].net_fd);
                    continue;
                }
                // 程序走到这里说明有客户端的数据->转发
                // 遍历所有客户端，转发
                for (int j = 0; j<size; j++)
                {
                    // 遍历到本身的客户端 或者 数组中的状态为0(已关闭net_fd)
                    if(i==j || list[j].alive == 0)
                    {
                        continue;
                    }
                    int res_send = send(list[j].net_fd, buf, sizeof(buf), 0);
                    ERROR_CHECK(res_send, -1, "send");
                }
            }
        }

    }
    close(socket_fd);
    close(list->net_fd);
    return 0;

}
